package com.cskaoyan.javase.array._4operation._3curd;

import java.io.PushbackInputStream;
import java.util.Arrays;
import java.util.Scanner;

/**
 * 数组是一个容器，可以用存放元素，存放数据。
 * 在实际开发中，工程中也会需要存放大量数据，这一般是通过数据库来实现的。
 * 数据库是用于持久化(永久)存储数据的工具.
 *
 * 实际开发的基本需求就是基于数据库的，对数据进行增删改查，即"crud"
 * 也有很多中低级Java程序员自嘲自己为"crud工程师"。
 *
 * 当然"crud"指的是：
 *      1.c，create：新增数据/增加。
 *      2.r，retrieve(query,search)：检索数据/查询。
 *      3.u，update：更新数据/修改。
 *      4.d，delete ：删除数据/删除。
 *
 * 程序在运行时,是在内存中运行的,Java程序执行在JVM内存中
 * 在内存中,数据的存储主要依靠各种容器,Java程序中主要依赖于高级容器集合
 * 集合也是基于数组诞生的
 *
 * 我们现在还没有学习过数据库，但是不重要。
 * 现在我们使用数组这个容器，来模拟数据库，实现日常开发中最常见的"crud"操作。
 *
 * 需求:
 *      用一个String类型的数组,来模拟装人名的数据库
 *      规定: 数组中的人名是唯一的,不可重复的
 *
 * @since 09:32
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 模拟数据源
        String[] names = new String[10];
        names[0] = "张三";
        names[1] = "李四";
        names[2] = "王二";
        names[3] = "麻子";
        names[4] = "李浩";
        names[5] = "陈伟";
        System.out.print("原始数组中的人名有:");
        printNames(names);
        /*System.out.println("开始测试插入人名.....");
        System.out.println("请键盘录入一个不重复的人名:");
        Scanner sc = new Scanner(System.in);
        String nameInsert = sc.nextLine();
        switch (createName(names, nameInsert)) {
            case 0:
                System.out.println("插入成功!");
                // 打印一下现在数组中的人名有哪些
                printNames(names);
                break;
            case 1:
                System.out.println("人名重复了,插入失败!");
                break;
            case 2:
                System.out.println("数组满了,插入失败!");
                break;
        }*/
        System.out.println("开始测试删除人名....");
        System.out.println("请键盘录入要被删除的人名:");
        Scanner sc = new Scanner(System.in);
        String nameDelete = sc.nextLine();
        if (deleteName(names, nameDelete)) {
            System.out.println("删除成功!");
            printNames(names);
        } else {
            System.out.println("未找到人名,删除失败!");
        }

        // 数组的长度不可变指的是堆上的对象不可变,而不是引用不可变
        // names = new String[20];

    }


    // 该方法用于打印人名数组中的元素,只打印具体人名,排除null元素

    /**
     * 直接在控制台打印人名数组中的人名,排除null元素
     *
     * @param target 被打印人名的目标数组
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/08/19 10:05
     */
    public static void printNames(String[] target) {
        System.out.print("[");
        for (String name : target) {
            if (name == null) {
                continue;
            }
            System.out.print(name + ", ");
        }
        System.out.println("\b\b]");
    }

    // 增
    /*
        分析一下新增的方法:
        数组可不可以真的新增一个元素?
        显然不可以,数组的长度是不可改变的,所以不可能真的新增一个元素
        所以这里的新增人名指的是:
        在原先的数组中,找到一个为null的位置,然后用一个字符串赋值.
        那么新增人名有几种结果可能?
            1.输入的人名重复了,新增失败了
            2.不存在null的位置,数组满了,新增失败
            3.如果不存在以上情况,那么新增成功
        所以该方法的执行,至少有三种结果
        那么如何写这种方法的返回值呢?
        方法返回一组状态码,用于指示方法调用的结果
        这里我们规定:
            如果方法返回0,表示新增成功
            如果方法返回1,表示人名重复,新增失败
            如果方法返回2,表示数组满了,新增失败
     */

    /**
     * 新增人名,根据不同的结果返回不同的状态码:
     *      如果方法返回0,表示新增成功
     *      如果方法返回1,表示人名重复,新增失败
     *      如果方法返回2,表示数组满了,新增失败
     *
     * @param target 被新增人名的数组
     * @param targetName 被新增的人名
     * @return int 方法调用完毕返回的状态码
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/08/19 9:46
     */
    public static int createName(String[] target, String targetName) {
    /*
            具体如何实现呢?
            大致思路是 遍历整个数组
                如果人名重复,直接新增失败
                如果人名没有重复,那就尝试插入
                    这种情况下,如果仍然插入失败
                        说明没有位置了
                    反之则插入成功
    */
        for (String name : target) {
            /*if (name == null) {
                // 如果name是null,肯定不可能重复,那就跳过这次循环避免空指针异常
                continue;
            }*/
            // 逐个比较,验证人名是否重复
            /*if (name.equals(targetName)) {
                // 重复了,插入失败
                return 1;
            }*/

            // targetName是键盘录入得到的,不可能为null,所以把它写在左边调用方法,避免空指针异常
            if (targetName.equals(name)) {
                // 重复了,插入失败
                return 1;
            }
        }
        // 代码运行到这里,人名必然是不重复的,于是开始找到一个null的位置,尝试插入(这个插入实际上是赋值,所以用普通for)
        for (int i = 0; i < target.length; i++) {
            if (target[i] == null) {
                // 找到null的位置,赋值,插入成功
                target[i] = targetName;
                return 0;
            }
        }
        // 代码运行到这里,表示还没插入成功,说明数组满了
        return 2;
    }
    // 删
    /*
        分析一下这个删除操作
        不可能真的删除数组中的某个元素
        这里的删除指的是用一个null来替换原本的字符串,所以实际上也是赋值
        对于删除来说,提供一个被删除的人名,其结果有:
            1.找到了目标人名,删除成功
            2.没有找到,没有这个人名,删除失败
        针对这种二元性结果的方法执行,返回值类型可以选择布尔类型
     */

    /**
     * 删除目标人名,规定:
     *      1.删除成功,返回true
     *      2.删除失败,返回false
     *
     * @param target 被删除人名的人名数组
     * @param nameTarget 被删除的目标人名
     * @return boolean
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/08/19 10:50
     */
    public static boolean deleteName(String[] target, String nameTarget) {
        // 遍历查找目标元素,找到了就赋值为null
        for (int i = 0; i < target.length; i++) {
            // 判断目标人名和数组中人名是否重复,重复就说明存在,删除掉(赋值为null)
            if (nameTarget.equals(target[i])) {
                // 找到了
                target[i] = null;
                return true;
            }
        }
        // 代码运行到这里,说明没找到目标元素,删除失败
        return false;
    }
    // 改
    // 查
}
